﻿using System.Collections.Generic;
using ReadyApps.Data.Wiki;

namespace ReadyApps.Data
{
    /// <summary>
    /// Provides an abstract data layer for the data access methods of a wiki page.
    /// </summary>
    /// <seealso cref="ReadyApps.Data.Oracle.OracleWikiDataProvider"/>
    /// <remarks>
    /// <h5>Notes to Implementers</h5>
    /// <para>
    /// To implement a custom data store for the wiki control, this interface must be implemented
    /// by the class. See each method for the <b>Notes to Implementers</b> section about
    /// implementation details. If a method has no documentation, it is not needed by the
    /// current version of the control and may be left as an empty method in implementations.
    /// Future versions of the control may use these currently undocumented methods, or their
    /// required inclusion removed from this interface.
    /// </para>
    /// <para>
    /// Page IDs and revision numbers are specified in many of the methods of the
    /// <see cref="IWikiDataProvider"/>. In the case that a page ID or page ID with revision
    /// number is not found in the data store, a <see cref="ReadyApps.Data.Exceptions.PageNotFoundException"/>
    /// should be thrown unless otherwise noted. The caller should then handle the exception
    /// appropriately.
    /// </para>
    /// </remarks>
    public interface IWikiDataProvider
    {
        /// <summary>
        /// Copies a previous version of a wiki page to the current revision.
        /// </summary>
        /// <param name="pageID">The page ID to clone a revision from.</param>
        /// <param name="revisionNumber">The revision number of the page content to
        /// copy to a new current revision for the page.</param>
        /// <param name="author">The user making the change.</param>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should create a new revision in the data source for the specified
        /// page. If the publishing workflow has been enabled for the page and there is a
        /// pending revision, the cloned revision should be inserted between the pending
        /// revision and the current revision and then become the current revision.
        /// </para>
        /// </remarks>
        void CloneRevisionToHead(int pageID, int revisionNumber, string author);

        /// <summary>
        /// Creates a new page within the given site and path with the specified page name.
        /// </summary>
        /// <param name="siteName">The site name create the page within.</param>
        /// <param name="fullPath">The full path to the new page.</param>
        /// <param name="pageName">The page name to create.</param>
        /// <param name="author">The user making the change.</param>
        /// <param name="content">A <see cref="PageContent"/> object with the content for the
        /// new page.</param>
        /// <seealso cref="PageContent"/>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should create a new page in the data store within the supplied site
        /// and folder hierarchy. The <paramref name="pageName"/> parameter is the URL that
        /// the end user of the page uses to access the page. The content object must not be
        /// null.
        /// </para>
        /// </remarks>
        void CreateNewPage(string siteName, string fullPath, string pageName, string author, PageContent content);

        /// <summary>
        /// Creates a new wiki site and its initial structure for use by wiki controls.
        /// </summary>
        /// <param name="siteName">The new site name to create.</param>
        /// <param name="securityEnabled">Indicates whether or not the new site should have
        /// site-wide security enabled.</param>
        /// <param name="initialPath">The minimum full path of folders to create within the
        /// new site.</param>
        /// <param name="creator">The user requesting the creation of the site.</param>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should create a new site in the data store in addition to all the folders
        /// specified in the <paramref name="initialPath"/> parameter. Each folder created should
        /// have a default page created within it with a revision number of zero. All of the
        /// parameters are required to be non-null and non-empty.
        /// </para>
        /// </remarks>
        void CreateNewSite(string siteName, bool securityEnabled, string initialPath, string creator);

        /// <summary>
        /// Deletes the pending revision for the specified page.
        /// </summary>
        /// <param name="pageID">The page ID to delete the pending revision for.</param>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should nullify any pending revisions for the supplied page based on the
        /// particular data store's design.
        /// </para>
        /// </remarks>
        void DeletePendingRevision(int pageID);

        /// <summary>
        /// Gets an <see cref="IEnumerable{AvailablePageLink}"/> collection of the internal
        /// wiki pages that can be linked to from the supplied page and control base.
        /// </summary>
        /// <param name="folder">The base folder of the wiki control.</param>
        /// <param name="pageID">The page ID of the page to link from.</param>
        /// <param name="removeSuppliedPage">A value indicating whether or not the requested
        /// page should be removed from the list of available links.</param>
        /// <returns>An <see cref="IEnumerable{AvailablePageLink}"/> collection of pages
        /// that can be linked to from the supplied wiki page.</returns>
        /// <seealso cref="AvailablePageLink"/>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should return all pages available in the <paramref name="pageID"/>
        /// parameter's site hierarchy within and recursively in all subfolders of the
        /// <paramref name="folder"/> parameter folder. If <paramref name="removeSuppliedPage"/>
        /// is <c>true</c>, the requested page should be removed from the results; otherwise,
        /// the requested page should be left in the results. If there are no pages that meet
        /// the above criteria, an empty collection should be returned.
        /// </para>
        /// </remarks>
        IEnumerable<AvailablePageLink> GetAvailablePageLinks(string folder, int pageID, bool removeSuppliedPage);

        /// <summary>
        /// Retrieves <see cref="EditPermissions"/> for editing the permissions of the
        /// given wiki page.
        /// </summary>
        /// <param name="pageID">The wiki page ID to retrieve permission editing information
        /// about.</param>
        /// <returns>A <see cref="EditPermissions"/> object with the appropriate wiki
        /// page information filled in.</returns>
        /// <seealso cref="EditPermissions"/>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// The <see cref="EditPermissions"/> return value should never be null and all the properties
        /// should be filled in according to the requirements of the <see cref="EditPermissions"/>
        /// class.
        /// </para>
        /// </remarks>
        EditPermissions GetEditPermissions(int pageID);

// Temporarily hide the XML comment not visible warning
#pragma warning disable 1591
        PermissionSet GetFolderPermissions(int folderID);
#pragma warning restore

        /// <summary>
        /// Retrieves a <see cref="PermissionSet"/> for the folder containing the specified page.
        /// </summary>
        /// <param name="pageID">The page ID of the page contained in the folder to get permissions
        /// for.</param>
        /// <returns>A <see cref="PermissionSet"/> object of the permissions applicable to a page's
        /// containing folder.</returns>
        /// <seealso cref="PermissionSet"/>
        /// <remarks>
        /// <h5>Notes for Implementers</h5>
        /// <para>
        /// This method should search up the folder hierarchy starting with the folder containing
        /// the supplied page ID for the first folder that has permissions defined for it and
        /// return those. Because the system assumes that the root folder of a security-enabled
        /// site will always have a permission set defined, this method should never return
        /// <c>null</c> and should be filled in according to the specifications of the
        /// <see cref="PermissionSet"/> class.
        /// </para>
        /// </remarks>
        PermissionSet GetFolderPermissionsForPage(int pageID);

        /// <summary>
        /// Gets <see cref="PageContent"/> for the current revision of the specified page.
        /// </summary>
        /// <param name="pageID">The page ID to retrieve current content for.</param>
        /// <returns>A <see cref="PageContent"/> object containing the content of the page.</returns>
        /// <seealso cref="PageContent"/>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should return a <see cref="PageContent"/> object filled in with data
        /// from the current revision of the page according to the specifications of the
        /// <see cref="PageContent"/> class. This method should never return <c>null</c>.
        /// </para>
        /// </remarks>
        PageContent GetPageContent(int pageID);

        /// <summary>
        /// Gets <see cref="PageContent"/> for the pending revision of the specified page.
        /// </summary>
        /// <param name="pageID">The page ID to retrieve pending content for.</param>
        /// <returns>A <see cref="PageContent"/> object containing the content of the page.</returns>
        /// <seealso cref="PageContent"/>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should return a <see cref="PageContent"/> object filled in with data
        /// from the pending revision of the page according to the specifications of the
        /// <see cref="PageContent"/> class. If a pending revision does not exist, the current
        /// revision of the page should be returned. This method should never return <c>null</c>.
        /// </para>
        /// </remarks>
        PageContent GetPageContentForPending(int pageID);

        /// <summary>
        /// Gets <see cref="PageContent"/> for the specified revision of a page.
        /// </summary>
        /// <param name="pageID">The page ID to retrieve revision content for.</param>
        /// <param name="revisionNumber">The specific revision number to retrieve content for.</param>
        /// <returns>A <see cref="PageContent"/> object containing the content of the page.</returns>
        /// <seealso cref="PageContent"/>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should return a <see cref="PageContent"/> object filled in with data
        /// from the specified revision of the page according to the specifications of the
        /// <see cref="PageContent"/> class. This method should never return <c>null</c>.
        /// </para>
        /// </remarks>
        PageContent GetPageContentForRevision(int pageID, int revisionNumber);

        /// <summary>
        /// Gets <see cref="PageDetails"/> for the specified page.
        /// </summary>
        /// <param name="pageID">The page ID to look up details for.</param>
        /// <returns>A <see cref="PageDetails"/> object containing the details about the
        /// page settings.</returns>
        /// <seealso cref="PageDetails"/>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should return a <see cref="PageDetails"/> object filled in according
        /// to the specifications of the <see cref="PageDetails"/> class. This method should
        /// never return <c>null</c>.
        /// </para>
        /// </remarks>
        PageDetails GetPageDetails(int pageID);

// Temporarily hide the XML comment not visible warning
#pragma warning disable 1591
        int GetPageFolder(int pageID);
#pragma warning restore

        /// <summary>
        /// Retrieves a <see cref="PermissionSet"/> for the specified page.
        /// </summary>
        /// <param name="pageID">The page ID to retrieve permissions for.</param>
        /// <param name="pageSpecificPermissions">Returns a value indicating whether or not
        /// the returned permissions are specific to a page.</param>
        /// <returns>A <see cref="PermissionSet"/> object of the permissions applicable to a
        /// page.</returns>
        /// <seealso cref="PermissionSet"/>
        /// <remarks>
        /// <h5>Notes for Implementers</h5>
        /// <para>
        /// This method should search up the folder hierarchy starting with the supplied page
        /// for the first permission set defined on either the page itself or its containing
        /// folders. Because the system assumes that the root folder of a security-enabled
        /// site will always have a permission set defined, this method should never return
        /// <c>null</c> and should be filled in according to the specifications of the
        /// <see cref="PermissionSet"/> class. The <paramref name="pageSpecificPermissions"/>
        /// parameter should be set to whether or not the permissions being returned are
        /// specific to the page or not.
        /// </para>
        /// </remarks>
        PermissionSet GetPagePermissions(int pageID, out bool pageSpecificPermissions);

        /// <summary>
        /// Gets an <see cref="IEnumerable{PageInformation}"/> collection of the available
        /// revisions of a wiki page.
        /// </summary>
        /// <param name="pageID">The page ID of the page to retrieve revision information
        /// for.</param>
        /// <returns>An <see cref="IEnumerable{PageInformation}"/> collection of the
        /// available revisions of a page.</returns>
        /// <seealso cref="PageInformation"/>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should always return an <see cref="IEnumerable{PageInformation}"/>
        /// collection with at least the current revision and all past revisions of the
        /// requested page.
        /// </para>
        /// </remarks>
        IEnumerable<PageInformation> GetPageRevisionList(int pageID);

// Temporarily hide the XML comment not visible warning
#pragma warning disable 1591
        IEnumerable<PageInformation> GetPagesInFolder(int folderID);
#pragma warning restore

        /// <summary>
        /// Gets the current page title for the specified page.
        /// </summary>
        /// <param name="pageID">The page ID of the page to retrieve the title for.</param>
        /// <returns>The title of the current revision of the page.</returns>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should return a non-null and non-empty string representing the title
        /// for the specified page's current revision.
        /// </para>
        /// </remarks>
        string GetPageTitle(int pageID);

        /// <summary>
        /// Gets the <see cref="PublicationSettings"/> applicable to the specified page.
        /// </summary>
        /// <param name="pageID">The page ID to find publication settings for.</param>
        /// <returns>A <see cref="PublicationSettings"/> object for the specified page.</returns>
        /// <seealso cref="PublicationSettings"/>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should return the <see cref="PublicationSettings"/> for the specified
        /// page filled in according to the specifications of the <see cref="PublicationSettings"/>
        /// class. This method should never return <c>null</c>.
        /// </para>
        /// </remarks>
        PublicationSettings GetPublicationSettings(int pageID);

        /// <summary>
        /// Gets the <see cref="RetentionSettings"/> applicable to the specified page.
        /// </summary>
        /// <param name="pageID">The page ID to find retention settings for.</param>
        /// <returns>A <see cref="RetentionSettings"/> object for the specified page.</returns>
        /// <seealso cref="RetentionSettings"/>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should return the <see cref="RetentionSettings"/> for the specified
        /// page filled in according to the specifications of the <see cref="RetentionSettings"/>
        /// class. This method should never return <c>null</c>.
        /// </para>
        /// </remarks>
        RetentionSettings GetRetentionSettings(int pageID);

        /// <summary>
        /// Attempts to find a page for the given site name, folder, and page name combination.
        /// </summary>
        /// <param name="siteName">The wiki site name.</param>
        /// <param name="folder">The full folder path that contains the page to retrieve.</param>
        /// <param name="pageName">The name of the page within the folder to retrieve.</param>
        /// <returns>A <see cref="PageLookup"/> object for the results of the lookup.</returns>
        /// <remarks>
        /// <h5>Notes for Implementers</h5>
        /// <para>
        /// All parameters are required. The <paramref name="siteName"/> should be searched
        /// case-sensitively. The <paramref name="folder"/> parameter is the full path within
        /// the site that contains the page and should be searched case-insensitively. The
        /// <paramref name="pageName"/> parameter is the name of the page and should be searched
        /// case-insensitively.
        /// </para>
        /// <para>
        /// If the site is not found in the data store, the method should return
        /// <see cref="P:ReadyApps.Data.Wiki.PageLookup.SiteNotFoundLookup"/>. If the page is not
        /// found in the data store, the method should return
        /// <see cref="P:ReadyApps.Data.Wiki.PageLookup.PageNotFoundLookup"/>. If the page is
        /// found in the data store, the <see cref="P:ReadyApps.Data.Wiki.PageLookup.Details"/>
        /// should be included.
        /// </para>
        /// </remarks>
        PageLookup LookupPage(string siteName, string folder, string pageName);

        /// <summary>
        /// Publishes the pending revision for the specified page.
        /// </summary>
        /// <param name="pageID">The page ID to publish a pending revision for.</param>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should mark the current revision as a past revision and mark the latest
        /// pending revision in the data store as the current revision.
        /// </para>
        /// </remarks>
        void PublishPage(int pageID);

        /// <summary>
        /// Removes the page-specific permissions for the given page.
        /// </summary>
        /// <param name="pageID">The page ID to remove specific permissions from.</param>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should update the page in the data store so that it no longer has
        /// permissions specific to itself.
        /// </para>
        /// </remarks>
        void RemovePageSpecificPermissions(int pageID);

        /// <summary>
        /// Saves edited permissions for a page.
        /// </summary>
        /// <param name="pageID">The page ID to store the edit permissions for.</param>
        /// <param name="editPermissionsData">The <see cref="EditPermissions"/> object
        /// containing the information to save in the data source.</param>
        /// <seealso cref="EditPermissions"/>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should update the permissions in the data store according to the
        /// specifications of the <see cref="EditPermissions"/> class.
        /// </para>
        /// </remarks>
        void SavePagePermissions(int pageID, EditPermissions editPermissionsData);

        /// <summary>
        /// Saves edited publication settings for a page.
        /// </summary>
        /// <param name="pageID">The page ID to store the publication settings for.</param>
        /// <param name="publicationSettings">The <see cref="PublicationSettings"/> object
        /// to save.</param>
        /// <seealso cref="PublicationSettings"/>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should update the publication settings in the data store according
        /// to the specifications of the <see cref="PublicationSettings"/> class.
        /// </para>
        /// </remarks>
        void SavePublicationSettings(int pageID, PublicationSettings publicationSettings);

        /// <summary>
        /// Saves edited retention settings for a page.
        /// </summary>
        /// <param name="retentionSettings">The <see cref="RetentionSettings"/> object
        /// to save.</param>
        /// <seealso cref="RetentionSettings"/>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should update the retention settings in the data store according
        /// to the specifications of the <see cref="RetentionSettings"/> class.
        /// </para>
        /// </remarks>
        void SaveRetentionSettings(RetentionSettings retentionSettings);

        /// <summary>
        /// Sets the connection string for the underlying data source.
        /// </summary>
        /// <param name="connectionString">The data store-specific connection string.</param>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method is called by the <see cref="ReadyApps.Data.WikiDataProviderFactory"/>
        /// once the concrete type has been instantiated and passes in the connection string from
        /// the configuration file. If the data store does not require any additional information
        /// from the configuration section, this may be implemented as an empty method. An
        /// implementation of the <see cref="IWikiDataProvider"/> interface that requires connection
        /// string information must maintain this value internally as it is only guaranteed to be
        /// called once upon object creation.
        /// </para>
        /// </remarks>
        void SetConnectionString(string connectionString);

        /// <summary>
        /// Updates the content of a page and optionally publishes it if the publishing
        /// workflow is enabled.
        /// </summary>
        /// <param name="pageID">The page ID to update content for.</param>
        /// <param name="author">The user who made the changes.</param>
        /// <param name="content">The <see cref="PageContent"/> to save.</param>
        /// <param name="publish">A value indicating whether or not to publish the new
        /// revision immediately.</param>
        /// <seealso cref="PageContent"/>
        /// <remarks>
        /// <h5>Notes to Implementers</h5>
        /// <para>
        /// This method should create a new revision in the data store for the given page
        /// containing the supplied page content in the <see cref="PageContent"/> object.
        /// If publishing is not enabled, the new revision should become the current
        /// revision. If publishing is enabled and <paramref name="publish"/> is <c>true</c>,
        /// the new revision should become the current revision. If publishing is enabled
        /// and there is a pending revision, the pending revision should be nullified
        /// according to the data store's scheme and replaced with the supplied page
        /// content. In all cases, after the revision statuses have been updated, the
        /// retention policy should be applied to clean up any revisions that are no longer
        /// needed.
        /// </para>
        /// </remarks>
        void UpdatePage(int pageID, string author, PageContent content, bool publish);
    }
}
